package com.gopay.checkorder.service.impl.bcdl;

import java.math.BigDecimal;

import javax.annotation.Resource;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BankBcdlOrderDAO;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.constants.bank.NuccConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BcdlMessage;
import com.gopay.common.domain.bank.BcdlResult;
import com.gopay.common.domain.bank.nucc.common.query.res.NuccQueryBodyRes;
import com.gopay.common.domain.bank.nucc.common.query.res.NuccQueryRes;
import com.gopay.common.domain.bis.BisBankBcdlOrder;
import com.gopay.common.domain.cashier.BankCardType;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.vo.CheckOrderResult;
import com.gopay.common.domain.cps.vo.InAccInfo;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.BcdlInteractRemoteService;

/**
 * 网联付款接口实现
 * 
 * @CheckBcdlOrderNuccPayImpl.java
 * @author zhengxue
 * @2018-1-24 下午1:43:36 www.gopay.com.cn Inc.All rights reserved.
 */
public class CheckBcdlOrderNuccPayImpl extends BaseBcdlOrderProcessImpl {
    private final static Logger logger = LoggerFactory.getLogger(CheckBcdlOrderNuccPayImpl.class);

    @Resource(name = "bankBcdlClient")
    private BcdlInteractRemoteService bankBcdlClient;
    @Resource(name = "bankBcdlOrderDAO")
    private BankBcdlOrderDAO bankBcdlOrderDAO;

    public BcdlResult sendBank(BankOrder bankOrder) {
        BcdlResult result = new BcdlResult();
        try {
            BcdlMessage base = buildMsg(bankOrder);
            logger.info("nuccpay bcdl send bank orderId: " + bankOrder.getOrderId());
            result = bankBcdlClient.sendBank(base);
            return result;
        } catch (Exception e) {
            logger.error("银企直连订单支付失败: " + bankOrder.getOrderId(), e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6066);
            return result;
        }
    }

    public BcdlMessage buildMsg(BankOrder bankOrder) throws GopayException {
        BcdlMessage bcdlMsg = new BcdlMessage();
        BisBankBcdlOrder bcdl = bankBcdlOrderDAO.findBankBcdlOrderById(bankOrder.getOutOrderId());
        ToStringBuilder.reflectionToString(bcdl);
        bcdlMsg.setBankBusProd(BisBankBusinessProd._09);
        bcdlMsg.setBank(bankOrder.getBankCode());
        bcdlMsg.setBankIntrChann(BisBankInterfaceChannel._18);
        bcdlMsg.setGopayBankOrderNo(bankOrder.getOrderId());
        bcdlMsg.setOrderId(bankOrder.getOrderId());
        bcdlMsg.setOutOrderId(bankOrder.getOutOrderId());

        bcdlMsg.setPobcBankCode(bcdl.getRecvPbocBankCode());// 央行代码
        bcdlMsg.setPbocBankName(bcdl.getRecvBankName());// 央行名称
        bcdlMsg.setPbocBankBranchCode(bcdl.getRecvBankPbocNum());// 联行号
        bcdlMsg.setPbocBankBranchName(bcdl.getRecvBankBranchName());// 联行名
        bcdlMsg.setRecvBankAcctNum(bcdl.getRecvBankAcctNum());// 账号
        bcdlMsg.setRecvBankAcctName(bcdl.getRecvBankAcctName());// 户名
        bcdlMsg.setRecvBankProvNo(bcdl.getRecvBankProvinceCode());// 省代码
        bcdlMsg.setRecvBankProvName(bcdl.getRecvBankProvinceName());// 省名称
        bcdlMsg.setRecvBankCityCode(bcdl.getRecvBankCityCode());// 城市代码
        bcdlMsg.setRecvBankCityName(bcdl.getRecvBankCityName());// 城市名称
        bcdlMsg.setDcblType(bcdl.getBcFlag());
        bcdlMsg.setSysIOFlg(bcdl.getCrossBank());
        bcdlMsg.setEmergency(bcdl.getUrgent());
        int sameCity = 0;
        if (StringUtils.equals(bcdlMsg.getRecvBankProvNo(), "01")
                || (bcdlMsg.getRecvBankProvName() != null && bcdlMsg.getRecvBankProvName().indexOf("北京") != -1)) {
            logger.info("bcdl sameCity: 1" + "==================");
            sameCity = 1;
        }
        bcdlMsg.setIsSameCity(sameCity);
        CpsGenMainOrder mainOrder = getMainOrder(bankOrder.getOrderId());
        if (mainOrder.getSettleAmt() == null) {
            throw new RuntimeException("bcdl结算金额为null");
        }
        bcdlMsg.setAmount(mainOrder.getSettleAmt());
        return bcdlMsg;
    }

    public CheckOrderResult checkOrder(BankOrder bankOrder, String target) {
        CheckOrderResult checkOrderResult = new CheckOrderResult();
        try {
            checkOrderResult.setSuccess(false);
            checkOrderResult.setOrderId(bankOrder.getOrderId());

            BcdlMessage base = new BcdlMessage();
            base.setBankOrderId(bankOrder.getOrderId());
            base.setOrderId(bankOrder.getOrderId());// 使用订单号
            base.setOutOrderId(bankOrder.getOutOrderId());// 使用外部订单号
            base.setBank(bankOrder.getBankCode());
            base.setBankIntrChann(BisBankInterfaceChannel._18);
            base.setOrderDate(DateUtils.format(bankOrder.getSendBankTm(), "yyyy-MM-dd HH:mm:ss"));

            BcdlResult result = new BcdlResult();
            logger.error("nuccpay bcdl check order BcdlMessage: "
                    + ToStringBuilder.reflectionToString(base, ToStringStyle.DEFAULT_STYLE));

            result = bankBcdlClient.query(base);

            logger.error("nuccpay bcdl check order result: " + result);

            if (result == null) {
                logger.error("bankBcdlClient fail. result is null");
                return checkOrderResult;
            }

            NuccQueryRes res = (NuccQueryRes) result.getDefaultModel();
            if (res == null) {
                // 查询订单为空
                logger.error("fail:orderId:" + bankOrder.getOrderId() + " errcode:"
                        + ProcCodeConstants.PROC_CODE_100E5062 + " err:bis query is null.");
                checkOrderResult.setErrCode(result.getResultCode());
                checkOrderResult.setErrMsg("bis query is null.");
                return checkOrderResult;
            }

            NuccQueryBodyRes resBody = res.getMsgBody();
            String sysRtnCd = resBody.getSysRtnInf().getSysRtnCd(); // 该笔订单查询交易的状态
            String sysRtnDesc = resBody.getSysRtnInf().getSysRtnDesc(); // 该笔订单查询交易的状态描述
            if (!NuccConstants.NUCC_SYSRTNCD_SUCCESS.equals(sysRtnCd)) {
                // 系统返回码错误，交易处理中
                logger.error("网联付款订单:" + bankOrder.getOrderId() + "系统返回码为:" + sysRtnCd + "，系统返回描述：" + sysRtnDesc);
                checkOrderResult.setErrMsg("查询交易系统描述：" + sysRtnDesc + "，查询交易系统返回码：" + sysRtnCd);
                return checkOrderResult;
            }

            String oriSysRtnCd = resBody.getBizInf().getOriSysRtnCd();// 原系统返回码
            String oriSysRtnDesc = resBody.getBizInf().getOriSysRtnDesc();// 原系统返回码说明
            String oriBizStsCd = resBody.getBizInf().getOriBizStsCd();// 原业务返回码
            String oriBizStsDesc = resBody.getBizInf().getOriBizStsDesc();// 原业务返回码说明
            String oriTrxStatus = resBody.getBizInf().getOriTrxStatus();// 原交易状态
            if (!StringUtils.isBlank(oriTrxStatus)) {
                if (NuccConstants.NUCC_TRXSTATUSCD_SUCCESS.equals(oriTrxStatus)
                        || NuccConstants.NUCC_EXCEPTION_SUCCESS.equals(oriTrxStatus)) {
                    // 交易成功
                    checkOrderResult.setSuccess(true);
                    checkOrderResult.setErrCode(ProcCodeConstants.PROC_CODE_100S1000);
                    InAccInfo accInfo = new InAccInfo();
                    accInfo.setOrderId(bankOrder.getOrderId());
                    String amount = resBody.getBizInf().getOriTrxAmt();
                    accInfo.setAmount(new BigDecimal(amount.substring(amount.indexOf("CNY") + 3, amount.length())));
                    accInfo.setRetCode("00");
                    accInfo.setCardType(BankCardType.Unknown.toString());
                    checkOrderResult.setAccInfo(accInfo);
                    logger.error("网联付款订单" + bankOrder.getOrderId() + "交易状态为:" + oriTrxStatus + "，交易成功。");
                } else if (NuccConstants.NUCC_TRXSTATUSCD_FAIL.equals(oriTrxStatus)
                        || NuccConstants.NUCC_EXCEPTION_FAIL.equals(oriTrxStatus)) {
                    // 交易失败
                    checkOrderResult.setBankFailure(true);
                    checkOrderResult.setErrCode(ProcCodeConstants.PROC_CODE_100E6027);
                    logger.error("网联付款订单" + bankOrder.getOrderId() + "交易状态为:" + oriTrxStatus + "，交易失败。");
                    checkOrderResult.setErrMsg("银行返回失败,原交易系统描述：" + resBody.getBizInf().getOriSysRtnDesc() + "，原交易业务描述："
                            + resBody.getBizInf().getOriBizStsDesc());
                } else if (NuccConstants.NUCC_TRXSTATUSCD_PROCESSING.equals(oriTrxStatus)) {
                    // 处理中
                    logger.error("网联付款订单" + bankOrder.getOrderId() + "交易状态为:" + oriTrxStatus + "，交易进行中。");
                    checkOrderResult.setErrMsg("银行返回处理中");
                } else {
                    logger.error("网联付款订单" + bankOrder.getOrderId() + "交易状态为:" + oriTrxStatus + "，交易进行中。");
                    checkOrderResult.setErrMsg("原交易系统描述：" + resBody.getBizInf().getOriSysRtnDesc() + "，原交易业务描述："
                            + resBody.getBizInf().getOriBizStsDesc());
                }
            } else {
                // 原交易系统返回码错误，交易处理中
                logger.error("网联付款订单:" + bankOrder.getOrderId() + "原系统返回码为:" + oriSysRtnCd + "，原系统返回描述："
                        + oriSysRtnDesc + ",原业务返回码为:" + oriBizStsCd + "，原业务返回描述：" + oriBizStsDesc);
                checkOrderResult.setErrMsg("查询交易原系统描述：" + sysRtnDesc + "，查询交易原系统返回码：" + ",原业务返回码:" + oriBizStsCd
                        + "，原业务返回描述：" + oriBizStsDesc);
            }
            return checkOrderResult;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("银企直连订单查询失败: " + bankOrder.getOrderId(), e);
            checkOrderResult.setErrCode(ProcCodeConstants.PROC_CODE_100E5062);
            checkOrderResult.setErrMsg("bis is too busy.");
            return checkOrderResult;
        }
    }
    
    public BcdlResult queryAcctDetail(Object object) {
        BcdlResult result = new BcdlResult();
        try {
            BcdlMessage base = (BcdlMessage) object;
            result = bankBcdlClient.queryAcctDetail(base);
            return result;
        } catch (Exception e) {
            logger.error("银企直连查询网银明细失败: ", e);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6049);
            return result;
        }
    }

}
